home *** CD-ROM | disk | FTP | other *** search
/ Chip 2007 January, February, March & April / Chip-Cover-CD-2007-02.iso / Pakiet bezpieczenstwa / mini Pentoo LiveCD 2006.1 / mpentoo-2006.1.iso / livecd.squashfs / usr / lib / python2.4 / smtpd.pyo (.txt) < prev    next >
Python Compiled Bytecode  |  2005-10-18  |  16KB  |  555 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyo (Python 2.4)
  3.  
  4. """An RFC 2821 smtp proxy.
  5.  
  6. Usage: %(program)s [options] [localhost:localport [remotehost:remoteport]]
  7.  
  8. Options:
  9.  
  10.     --nosetuid
  11.     -n
  12.         This program generally tries to setuid `nobody', unless this flag is
  13.         set.  The setuid call will fail if this program is not run as root (in
  14.         which case, use this flag).
  15.  
  16.     --version
  17.     -V
  18.         Print the version number and exit.
  19.  
  20.     --class classname
  21.     -c classname
  22.         Use `classname' as the concrete SMTP proxy class.  Uses `PureProxy' by
  23.         default.
  24.  
  25.     --debug
  26.     -d
  27.         Turn on debugging prints.
  28.  
  29.     --help
  30.     -h
  31.         Print this message and exit.
  32.  
  33. Version: %(__version__)s
  34.  
  35. If localhost is not given then `localhost' is used, and if localport is not
  36. given then 8025 is used.  If remotehost is not given then `localhost' is used,
  37. and if remoteport is not given, then 25 is used.
  38. """
  39. import sys
  40. import os
  41. import errno
  42. import getopt
  43. import time
  44. import socket
  45. import asyncore
  46. import asynchat
  47. __all__ = [
  48.     'SMTPServer',
  49.     'DebuggingServer',
  50.     'PureProxy',
  51.     'MailmanProxy']
  52. program = sys.argv[0]
  53. __version__ = 'Python SMTP proxy version 0.2'
  54.  
  55. class Devnull:
  56.     
  57.     def write(self, msg):
  58.         pass
  59.  
  60.     
  61.     def flush(self):
  62.         pass
  63.  
  64.  
  65. DEBUGSTREAM = Devnull()
  66. NEWLINE = '\n'
  67. EMPTYSTRING = ''
  68. COMMASPACE = ', '
  69.  
  70. def usage(code, msg = ''):
  71.     print >>sys.stderr, __doc__ % globals()
  72.     if msg:
  73.         print >>sys.stderr, msg
  74.     
  75.     sys.exit(code)
  76.  
  77.  
  78. class SMTPChannel(asynchat.async_chat):
  79.     COMMAND = 0
  80.     DATA = 1
  81.     
  82.     def __init__(self, server, conn, addr):
  83.         asynchat.async_chat.__init__(self, conn)
  84.         self._SMTPChannel__server = server
  85.         self._SMTPChannel__conn = conn
  86.         self._SMTPChannel__addr = addr
  87.         self._SMTPChannel__line = []
  88.         self._SMTPChannel__state = self.COMMAND
  89.         self._SMTPChannel__greeting = 0
  90.         self._SMTPChannel__mailfrom = None
  91.         self._SMTPChannel__rcpttos = []
  92.         self._SMTPChannel__data = ''
  93.         self._SMTPChannel__fqdn = socket.getfqdn()
  94.         self._SMTPChannel__peer = conn.getpeername()
  95.         print >>DEBUGSTREAM, 'Peer:', repr(self._SMTPChannel__peer)
  96.         self.push('220 %s %s' % (self._SMTPChannel__fqdn, __version__))
  97.         self.set_terminator('\r\n')
  98.  
  99.     
  100.     def push(self, msg):
  101.         asynchat.async_chat.push(self, msg + '\r\n')
  102.  
  103.     
  104.     def collect_incoming_data(self, data):
  105.         self._SMTPChannel__line.append(data)
  106.  
  107.     
  108.     def found_terminator(self):
  109.         line = EMPTYSTRING.join(self._SMTPChannel__line)
  110.         print >>DEBUGSTREAM, 'Data:', repr(line)
  111.         self._SMTPChannel__line = []
  112.         if self._SMTPChannel__state == self.COMMAND:
  113.             if not line:
  114.                 self.push('500 Error: bad syntax')
  115.                 return None
  116.             
  117.             method = None
  118.             i = line.find(' ')
  119.             if i < 0:
  120.                 command = line.upper()
  121.                 arg = None
  122.             else:
  123.                 command = line[:i].upper()
  124.                 arg = line[i + 1:].strip()
  125.             method = getattr(self, 'smtp_' + command, None)
  126.             if not method:
  127.                 self.push('502 Error: command "%s" not implemented' % command)
  128.                 return None
  129.             
  130.             method(arg)
  131.             return None
  132.         elif self._SMTPChannel__state != self.DATA:
  133.             self.push('451 Internal confusion')
  134.             return None
  135.         
  136.         data = []
  137.         for text in line.split('\r\n'):
  138.             if text and text[0] == '.':
  139.                 data.append(text[1:])
  140.                 continue
  141.             data.append(text)
  142.         
  143.         self._SMTPChannel__data = NEWLINE.join(data)
  144.         status = self._SMTPChannel__server.process_message(self._SMTPChannel__peer, self._SMTPChannel__mailfrom, self._SMTPChannel__rcpttos, self._SMTPChannel__data)
  145.         self._SMTPChannel__rcpttos = []
  146.         self._SMTPChannel__mailfrom = None
  147.         self._SMTPChannel__state = self.COMMAND
  148.         self.set_terminator('\r\n')
  149.         if not status:
  150.             self.push('250 Ok')
  151.         else:
  152.             self.push(status)
  153.  
  154.     
  155.     def smtp_HELO(self, arg):
  156.         if not arg:
  157.             self.push('501 Syntax: HELO hostname')
  158.             return None
  159.         
  160.         if self._SMTPChannel__greeting:
  161.             self.push('503 Duplicate HELO/EHLO')
  162.         else:
  163.             self._SMTPChannel__greeting = arg
  164.             self.push('250 %s' % self._SMTPChannel__fqdn)
  165.  
  166.     
  167.     def smtp_NOOP(self, arg):
  168.         if arg:
  169.             self.push('501 Syntax: NOOP')
  170.         else:
  171.             self.push('250 Ok')
  172.  
  173.     
  174.     def smtp_QUIT(self, arg):
  175.         self.push('221 Bye')
  176.         self.close_when_done()
  177.  
  178.     
  179.     def __getaddr(self, keyword, arg):
  180.         address = None
  181.         keylen = len(keyword)
  182.         if arg[:keylen].upper() == keyword:
  183.             address = arg[keylen:].strip()
  184.             if not address:
  185.                 pass
  186.             elif address[0] == '<' and address[-1] == '>' and address != '<>':
  187.                 address = address[1:-1]
  188.             
  189.         
  190.         return address
  191.  
  192.     
  193.     def smtp_MAIL(self, arg):
  194.         print >>DEBUGSTREAM, '===> MAIL', arg
  195.         address = self._SMTPChannel__getaddr('FROM:', arg)
  196.         if not address:
  197.             self.push('501 Syntax: MAIL FROM:<address>')
  198.             return None
  199.         
  200.         if self._SMTPChannel__mailfrom:
  201.             self.push('503 Error: nested MAIL command')
  202.             return None
  203.         
  204.         self._SMTPChannel__mailfrom = address
  205.         print >>DEBUGSTREAM, 'sender:', self._SMTPChannel__mailfrom
  206.         self.push('250 Ok')
  207.  
  208.     
  209.     def smtp_RCPT(self, arg):
  210.         print >>DEBUGSTREAM, '===> RCPT', arg
  211.         if not self._SMTPChannel__mailfrom:
  212.             self.push('503 Error: need MAIL command')
  213.             return None
  214.         
  215.         address = self._SMTPChannel__getaddr('TO:', arg)
  216.         if not address:
  217.             self.push('501 Syntax: RCPT TO: <address>')
  218.             return None
  219.         
  220.         self._SMTPChannel__rcpttos.append(address)
  221.         print >>DEBUGSTREAM, 'recips:', self._SMTPChannel__rcpttos
  222.         self.push('250 Ok')
  223.  
  224.     
  225.     def smtp_RSET(self, arg):
  226.         if arg:
  227.             self.push('501 Syntax: RSET')
  228.             return None
  229.         
  230.         self._SMTPChannel__mailfrom = None
  231.         self._SMTPChannel__rcpttos = []
  232.         self._SMTPChannel__data = ''
  233.         self._SMTPChannel__state = self.COMMAND
  234.         self.push('250 Ok')
  235.  
  236.     
  237.     def smtp_DATA(self, arg):
  238.         if not self._SMTPChannel__rcpttos:
  239.             self.push('503 Error: need RCPT command')
  240.             return None
  241.         
  242.         if arg:
  243.             self.push('501 Syntax: DATA')
  244.             return None
  245.         
  246.         self._SMTPChannel__state = self.DATA
  247.         self.set_terminator('\r\n.\r\n')
  248.         self.push('354 End data with <CR><LF>.<CR><LF>')
  249.  
  250.  
  251.  
  252. class SMTPServer(asyncore.dispatcher):
  253.     
  254.     def __init__(self, localaddr, remoteaddr):
  255.         self._localaddr = localaddr
  256.         self._remoteaddr = remoteaddr
  257.         asyncore.dispatcher.__init__(self)
  258.         self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
  259.         self.set_reuse_addr()
  260.         self.bind(localaddr)
  261.         self.listen(5)
  262.         print >>DEBUGSTREAM, '%s started at %s\n\tLocal addr: %s\n\tRemote addr:%s' % (self.__class__.__name__, time.ctime(time.time()), localaddr, remoteaddr)
  263.  
  264.     
  265.     def handle_accept(self):
  266.         (conn, addr) = self.accept()
  267.         print >>DEBUGSTREAM, 'Incoming connection from %s' % repr(addr)
  268.         channel = SMTPChannel(self, conn, addr)
  269.  
  270.     
  271.     def process_message(self, peer, mailfrom, rcpttos, data):
  272.         """Override this abstract method to handle messages from the client.
  273.  
  274.         peer is a tuple containing (ipaddr, port) of the client that made the
  275.         socket connection to our smtp port.
  276.  
  277.         mailfrom is the raw address the client claims the message is coming
  278.         from.
  279.  
  280.         rcpttos is a list of raw addresses the client wishes to deliver the
  281.         message to.
  282.  
  283.         data is a string containing the entire full text of the message,
  284.         headers (if supplied) and all.  It has been `de-transparencied'
  285.         according to RFC 821, Section 4.5.2.  In other words, a line
  286.         containing a `.' followed by other text has had the leading dot
  287.         removed.
  288.  
  289.         This function should return None, for a normal `250 Ok' response;
  290.         otherwise it returns the desired response string in RFC 821 format.
  291.  
  292.         """
  293.         raise NotImplementedError
  294.  
  295.  
  296.  
  297. class DebuggingServer(SMTPServer):
  298.     
  299.     def process_message(self, peer, mailfrom, rcpttos, data):
  300.         inheaders = 1
  301.         lines = data.split('\n')
  302.         print '---------- MESSAGE FOLLOWS ----------'
  303.         for line in lines:
  304.             if inheaders and not line:
  305.                 print 'X-Peer:', peer[0]
  306.                 inheaders = 0
  307.             
  308.             print line
  309.         
  310.         print '------------ END MESSAGE ------------'
  311.  
  312.  
  313.  
  314. class PureProxy(SMTPServer):
  315.     
  316.     def process_message(self, peer, mailfrom, rcpttos, data):
  317.         lines = data.split('\n')
  318.         i = 0
  319.         for line in lines:
  320.             if not line:
  321.                 break
  322.             
  323.             i += 1
  324.         
  325.         lines.insert(i, 'X-Peer: %s' % peer[0])
  326.         data = NEWLINE.join(lines)
  327.         refused = self._deliver(mailfrom, rcpttos, data)
  328.         print >>DEBUGSTREAM, 'we got some refusals:', refused
  329.  
  330.     
  331.     def _deliver(self, mailfrom, rcpttos, data):
  332.         import smtplib as smtplib
  333.         refused = { }
  334.         
  335.         try:
  336.             s = smtplib.SMTP()
  337.             s.connect(self._remoteaddr[0], self._remoteaddr[1])
  338.             
  339.             try:
  340.                 refused = s.sendmail(mailfrom, rcpttos, data)
  341.             finally:
  342.                 s.quit()
  343.  
  344.         except smtplib.SMTPRecipientsRefused:
  345.             e = None
  346.             print >>DEBUGSTREAM, 'got SMTPRecipientsRefused'
  347.             refused = e.recipients
  348.         except (socket.error, smtplib.SMTPException):
  349.             e = None
  350.             print >>DEBUGSTREAM, 'got', e.__class__
  351.             errcode = getattr(e, 'smtp_code', -1)
  352.             errmsg = getattr(e, 'smtp_error', 'ignore')
  353.             for r in rcpttos:
  354.                 refused[r] = (errcode, errmsg)
  355.             
  356.  
  357.         return refused
  358.  
  359.  
  360.  
  361. class MailmanProxy(PureProxy):
  362.     
  363.     def process_message(self, peer, mailfrom, rcpttos, data):
  364.         StringIO = StringIO
  365.         import cStringIO
  366.         Utils = Utils
  367.         import Mailman
  368.         Message = Message
  369.         import Mailman
  370.         MailList = MailList
  371.         import Mailman
  372.         listnames = []
  373.         for rcpt in rcpttos:
  374.             local = rcpt.lower().split('@')[0]
  375.             parts = local.split('-')
  376.             if len(parts) > 2:
  377.                 continue
  378.             
  379.             listname = parts[0]
  380.             if len(parts) == 2:
  381.                 command = parts[1]
  382.             else:
  383.                 command = ''
  384.             if not Utils.list_exists(listname) or command not in ('', 'admin', 'owner', 'request', 'join', 'leave'):
  385.                 continue
  386.             
  387.             listnames.append((rcpt, listname, command))
  388.         
  389.         for rcpt, listname, command in listnames:
  390.             rcpttos.remove(rcpt)
  391.         
  392.         print >>DEBUGSTREAM, 'forwarding recips:', ' '.join(rcpttos)
  393.         if rcpttos:
  394.             refused = self._deliver(mailfrom, rcpttos, data)
  395.             print >>DEBUGSTREAM, 'we got refusals:', refused
  396.         
  397.         mlists = { }
  398.         s = StringIO(data)
  399.         msg = Message.Message(s)
  400.         if not msg.getheader('from'):
  401.             msg['From'] = mailfrom
  402.         
  403.         if not msg.getheader('date'):
  404.             msg['Date'] = time.ctime(time.time())
  405.         
  406.         for rcpt, listname, command in listnames:
  407.             print >>DEBUGSTREAM, 'sending message to', rcpt
  408.             mlist = mlists.get(listname)
  409.             if not mlist:
  410.                 mlist = MailList.MailList(listname, lock = 0)
  411.                 mlists[listname] = mlist
  412.             
  413.             if command == '':
  414.                 msg.Enqueue(mlist, tolist = 1)
  415.                 continue
  416.             if command == 'admin':
  417.                 msg.Enqueue(mlist, toadmin = 1)
  418.                 continue
  419.             if command == 'owner':
  420.                 msg.Enqueue(mlist, toowner = 1)
  421.                 continue
  422.             if command == 'request':
  423.                 msg.Enqueue(mlist, torequest = 1)
  424.                 continue
  425.             if command in ('join', 'leave'):
  426.                 if command == 'join':
  427.                     msg['Subject'] = 'subscribe'
  428.                 else:
  429.                     msg['Subject'] = 'unsubscribe'
  430.                 msg.Enqueue(mlist, torequest = 1)
  431.                 continue
  432.         
  433.  
  434.  
  435.  
  436. class Options:
  437.     setuid = 1
  438.     classname = 'PureProxy'
  439.  
  440.  
  441. def parseargs():
  442.     global DEBUGSTREAM
  443.     
  444.     try:
  445.         (opts, args) = getopt.getopt(sys.argv[1:], 'nVhc:d', [
  446.             'class=',
  447.             'nosetuid',
  448.             'version',
  449.             'help',
  450.             'debug'])
  451.     except getopt.error:
  452.         e = None
  453.         usage(1, e)
  454.  
  455.     options = Options()
  456.     for opt, arg in opts:
  457.         if opt in ('-h', '--help'):
  458.             usage(0)
  459.             continue
  460.         if opt in ('-V', '--version'):
  461.             print >>sys.stderr, __version__
  462.             sys.exit(0)
  463.             continue
  464.         if opt in ('-n', '--nosetuid'):
  465.             options.setuid = 0
  466.             continue
  467.         if opt in ('-c', '--class'):
  468.             options.classname = arg
  469.             continue
  470.         if opt in ('-d', '--debug'):
  471.             DEBUGSTREAM = sys.stderr
  472.             continue
  473.     
  474.     if len(args) < 1:
  475.         localspec = 'localhost:8025'
  476.         remotespec = 'localhost:25'
  477.     elif len(args) < 2:
  478.         localspec = args[0]
  479.         remotespec = 'localhost:25'
  480.     elif len(args) < 3:
  481.         localspec = args[0]
  482.         remotespec = args[1]
  483.     else:
  484.         usage(1, 'Invalid arguments: %s' % COMMASPACE.join(args))
  485.     i = localspec.find(':')
  486.     if i < 0:
  487.         usage(1, 'Bad local spec: %s' % localspec)
  488.     
  489.     options.localhost = localspec[:i]
  490.     
  491.     try:
  492.         options.localport = int(localspec[i + 1:])
  493.     except ValueError:
  494.         usage(1, 'Bad local port: %s' % localspec)
  495.  
  496.     i = remotespec.find(':')
  497.     if i < 0:
  498.         usage(1, 'Bad remote spec: %s' % remotespec)
  499.     
  500.     options.remotehost = remotespec[:i]
  501.     
  502.     try:
  503.         options.remoteport = int(remotespec[i + 1:])
  504.     except ValueError:
  505.         usage(1, 'Bad remote port: %s' % remotespec)
  506.  
  507.     return options
  508.  
  509. if __name__ == '__main__':
  510.     options = parseargs()
  511.     if options.setuid:
  512.         
  513.         try:
  514.             import pwd
  515.         except ImportError:
  516.             print >>sys.stderr, 'Cannot import module "pwd"; try running with -n option.'
  517.             sys.exit(1)
  518.  
  519.         nobody = pwd.getpwnam('nobody')[2]
  520.         
  521.         try:
  522.             os.setuid(nobody)
  523.         except OSError:
  524.             e = None
  525.             if e.errno != errno.EPERM:
  526.                 raise 
  527.             
  528.             print >>sys.stderr, 'Cannot setuid "nobody"; try running with -n option.'
  529.             sys.exit(1)
  530.         except:
  531.             None<EXCEPTION MATCH>OSError
  532.         
  533.  
  534.     None<EXCEPTION MATCH>OSError
  535.     classname = options.classname
  536.     if '.' in classname:
  537.         lastdot = classname.rfind('.')
  538.         mod = __import__(classname[:lastdot], globals(), locals(), [
  539.             ''])
  540.         classname = classname[lastdot + 1:]
  541.     else:
  542.         import __main__ as mod
  543.     class_ = getattr(mod, classname)
  544.     proxy = class_((options.localhost, options.localport), (options.remotehost, options.remoteport))
  545.     
  546.     try:
  547.         asyncore.loop()
  548.     except KeyboardInterrupt:
  549.         pass
  550.     except:
  551.         None<EXCEPTION MATCH>KeyboardInterrupt
  552.     
  553.  
  554. None<EXCEPTION MATCH>KeyboardInterrupt
  555.